package com.wang.tool.serialize;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * use fastjson with WriteClassName
 *
 * @see SerializerFeature#WriteClassName
 */
public class GenericFastJsonUtil {


    /**
     * @param object
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#deserialize(byte[])
     * @see GenericFastJsonUtil#deserialize(byte[], Type)
     */
    public static byte[] serialize(Object object) throws SerializationException {
        if (object == null) {
            return new byte[0];
        }
        try {
            return JSON.toJSONBytes(object, SerializerFeature.WriteClassName,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteNonStringKeyAsString);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.SERIALIZE_ERROR, "Could not write JSON: " + e.getMessage());
        }
    }

    /**
     * @param source
     * @param <T>
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#serialize(Object)
     */
    public static <T> T deserialize(byte[] source) throws SerializationException {
        if (source == null || source.length == 0) {
            return null;
        }
        try {
            return JSON.parseObject(source, Object.class, Feature.SupportAutoType, Feature.IgnoreNotMatch, Feature.SupportNonPublicField);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.DESERIALIZE_ERROR, "Could not read JSON:  " + e.getMessage());
        }
    }

    /**
     * 反序列化时指定类型
     *
     * @param source
     * @param type
     * @param <T>
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#serialize(Object)
     */
    public static <T> T deserialize(byte[] source, Type type) throws SerializationException {
        if (source == null || source.length == 0) {
            return null;
        }
        T oriObj = deserialize(source);
        if (oriObj == null) {
            return null;
        }

        if (type == null || type == Object.class) {
            return oriObj;
        }
        //        无泛型且继承关系
        if (!(type instanceof ParameterizedType) && type instanceof Class<?> && ((Class<?>) type).isInstance(oriObj)) {
            return oriObj;
        }
        try {
            byte[] bytes = JSON.toJSONBytes(oriObj,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteNonStringKeyAsString);
            return JSON.parseObject(bytes, type, Feature.DisableSpecialKeyDetect, Feature.IgnoreAutoType, Feature.IgnoreNotMatch, Feature.SupportNonPublicField);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.DESERIALIZE_ERROR, "Could not read JSON: " + e.getMessage());
        }
    }


    /**
     * @param object
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#deserializeFromStr(String, Type)
     * @see GenericFastJsonUtil#deserializeFromStr(String)
     */
    public static String serializeToStr(Object object) throws SerializationException {
        if (object == null) {
            return null;
        }
        try {
            return JSON.toJSONString(object, SerializerFeature.WriteClassName,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteNonStringKeyAsString);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.SERIALIZE_ERROR, "Could not write JSON: " + e.getMessage());
        }
    }

    /**
     * @param source
     * @param <T>
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#serializeToStr(Object)
     */
    public static <T> T deserializeFromStr(String source) throws SerializationException {
        if (source == null || source.isEmpty()) {
            return null;
        }
        try {
            return (T) JSON.parseObject(source, Object.class, Feature.SupportAutoType, Feature.IgnoreNotMatch, Feature.SupportNonPublicField);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.DESERIALIZE_ERROR, "Could not read JSON:  " + e.getMessage());
        }
    }

    /**
     * 反序列化时指定类型
     *
     * @param source
     * @param type
     * @param <T>
     * @return
     * @throws SerializationException
     * @see GenericFastJsonUtil#serializeToStr(Object)
     */
    public static <T> T deserializeFromStr(String source, Type type) throws SerializationException {
        if (source == null || source.isEmpty()) {
            return null;
        }
        T oriObj = deserializeFromStr(source);
        if (oriObj == null) {
            return null;
        }

        if (type == null || type == Object.class) {
            return oriObj;
        }
        //        无泛型且继承关系
        if (!(type instanceof ParameterizedType) && type instanceof Class<?> && ((Class<?>) type).isInstance(oriObj)) {
            return oriObj;
        }
        try {
            byte[] bytes = JSON.toJSONBytes(oriObj,SerializerFeature.WriteEnumUsingToString,SerializerFeature.WriteNonStringKeyAsString);
            return JSON.parseObject(bytes, type, Feature.DisableSpecialKeyDetect, Feature.IgnoreAutoType, Feature.IgnoreNotMatch, Feature.SupportNonPublicField);
        } catch (Throwable e) {
            throw new SerializationException(e, SerializationException.DESERIALIZE_ERROR, "Could not read JSON: " + e.getMessage());
        }
    }
}